package com.op.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.op.constants.CommonStatusConstant;
import com.op.constants.FileSuffixConstant;
import com.op.constants.NumberConstant;
import com.op.constants.OtherConstant;
import com.op.converter.QuestionConverter;
import com.op.entity.Question;
import com.op.entity.QuestionBank;
import com.op.entity.QuestionBankAudit;
import com.op.mapper.QuestionBankMapper;
import com.op.model.vo.QuestionBankOfQuestionVo;
import com.op.service.QuestionBankAuditService;
import com.op.service.QuestionBankService;
import com.op.service.QuestionService;
import com.op.util.FileUtil;
import io.minio.errors.MinioException;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * (QuestionBank)表服务实现类
 *
 * @author 孤焰
 * @since 2021-10-05 10:30:32
 */
@Service("questionBankService")
public class QuestionBankServiceImpl extends ServiceImpl<QuestionBankMapper, QuestionBank> implements QuestionBankService {

    @Resource
    QuestionBankMapper questionBankMapper;
    @Resource
    QuestionService questionService;
    @Resource
    QuestionBankAuditService questionBankAuditService;

    @Override
    public List<QuestionBank> ownerBank(QuestionBank questionBank) {
        LambdaQueryWrapper<QuestionBank> lambdaQueryWrapper = Wrappers.lambdaQuery();
        // 私有 isCommon 0, 2 userId当前userId
        // 共有 isCommon 1, 2
        // isCommon == null，返回所有公有和userId下的题库
        lambdaQueryWrapper.eq(QuestionBank::getStatus, NumberConstant.ENABLE);
        if (questionBank.getIsCommon() == null) {
            lambdaQueryWrapper.eq(QuestionBank::getIsCommon, CommonStatusConstant.IS_COMMON)
                    .or()
                    .eq(QuestionBank::getUserId, questionBank.getUserId());
        } else {
            lambdaQueryWrapper.in(QuestionBank::getIsCommon, questionBank.getIsCommon(), CommonStatusConstant.BOTH_STATUS)
                    .eq(CommonStatusConstant.NO_COMMON.equals(questionBank.getIsCommon()), QuestionBank::getUserId, questionBank.getUserId());
        }

        return questionBankMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(QuestionBank questionBank, MultipartFile imgFile) throws IOException, InvalidKeyException, NoSuchAlgorithmException, MinioException {
        String imgPath = FileUtil.uploadImg(imgFile);
        questionBank.setImgPath(imgPath);
        return questionBankMapper.insert(questionBank) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(QuestionBank questionBank, MultipartFile imgFile) throws MinioException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        if (imgFile != null) {
            questionBank.setImgPath(FileUtil.uploadImg(imgFile));
        }
        return questionBankMapper.updateById(questionBank) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(QuestionBank questionBank, MultipartFile imgFile) throws MinioException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        if (imgFile != null) {
            questionBank.setImgPath(FileUtil.uploadImg(imgFile));
        }
        if (questionBank.getId() == null) {
            return questionBankMapper.insert(questionBank) > 0;
        } else {
            return questionBankMapper.updateById(questionBank) > 0;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateAudit(QuestionBank questionBank, MultipartFile imgFile) throws MinioException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        // TODO 增加权限控制  只有管理员才可以看到公共题库的添加和编辑按钮  所以只有私有题库的修改才会进入此方法
        // 私有题库修改情况下 先把私有题库的其他信息修改 再提交转换为公共题库的申请
        if (questionBank.getId() != null && CommonStatusConstant.BOTH_STATUS.equals(questionBank.getIsCommon())) {
            questionBank.setIsCommon(0);
            // 修改其他信息
            updateById(questionBank, imgFile);
            // 提交转换公共题库的申请
            return questionBankAuditService.save(new QuestionBankAudit(null, questionBank.getId(), CommonStatusConstant.BOTH_STATUS));
        }

        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicDelBatchById(List<Long> idList) {
        for (Long id : idList) {
            QuestionBank questionBank = new QuestionBank();
            questionBank.setId(id);
            questionBank.setStatus(NumberConstant.DISABLE);
            if (questionBankMapper.updateById(questionBank) <= 0) {
                throw new RuntimeException("部分删除失败");
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean upload(Long userId, MultipartFile file) throws Exception {
        String suffix = FilenameUtils.getExtension(file.getOriginalFilename());
        if (FileSuffixConstant.XLS.equalsIgnoreCase(suffix) || FileSuffixConstant.XLSX.equalsIgnoreCase(suffix)) {
            return uploadExcel(userId, file);
        } else {
            throw new Exception("不支持文件类型为:" + suffix);
        }
    }

    @Override
    public boolean export(List<Long> bankIds, HttpServletResponse response) throws IOException {
        // 设置response流
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(("题库excel" + ".xlsx").getBytes(), "iso-8859-1"));
        // 创建excel并设置内容
        List<QuestionBank> questionBanks = questionBankMapper.selectBatchIds(bankIds);
        Workbook workbook = new XSSFWorkbook();
        SimpleDateFormat sdf = new SimpleDateFormat(OtherConstant.DATE_FORMAT);
        for (QuestionBank questionBank : questionBanks) {
            LambdaQueryWrapper<Question> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Question::getBankId, questionBank.getId());
            List<Question> questions = questionService.list(lambdaQueryWrapper);
            Sheet sheet = workbook.createSheet(questionBank.getBankName());
            // 设置标题头
            setRow(sheet.createRow(0), 0,
                    "序号", "题目", "答案", "标签",
                    "题目难度", "备注", "状态", "创建时间", "更新时间");
            // 设置单元格内容
            for (int i = 1; i <= questions.size(); i++) {
                Question question = questions.get(i - 1);
                Row row = sheet.createRow(i);
                row.createCell(0).setCellValue(i);
                setRow(row, 1,
                        question.getProblem(), question.getSolution(),
                        question.getTags(), QuestionConverter.convertDiffIntToString(question.getDifficulty()),
                        question.getRemark(), QuestionConverter.convertStatusIntToString(question.getStatus()),
                        sdf.format(question.getCreateTime()), sdf.format(question.getModifyTime()));
            }
        }
        workbook.write(response.getOutputStream());
        workbook.close();

        return true;
    }

    @Override
    public List<QuestionBankOfQuestionVo> questionBelongBank(List<Question> questionList, List<Long> bankIdList) {
        List<QuestionBank> questionBankList = questionBankMapper.selectBatchIds(bankIdList);
        List<QuestionBankOfQuestionVo> questionBankOfQuestionVoList = new ArrayList<>();
        questionBankList.forEach(questionBank -> {
            QuestionBankOfQuestionVo questionBankOfQuestionVo = new QuestionBankOfQuestionVo();
            List<String> questionListVo = new ArrayList<>();
            questionList.forEach(question -> {
                if (questionBank.getId().equals(question.getBankId())) {
                    questionListVo.add(question.getProblem());
                }
            });
            questionBankOfQuestionVo.setQuestionList(questionListVo);
            questionBankOfQuestionVo.setBankName(questionBank.getBankName());
            questionBankOfQuestionVoList.add(questionBankOfQuestionVo);
        });
        return questionBankOfQuestionVoList;
    }

    /**
     * excel文件上传题库
     *
     * @param userId 用户id
     * @param excel  excel文件
     * @return 上传结果
     */
    private boolean uploadExcel(Long userId, MultipartFile excel) throws Exception {
        Workbook workbook;
        String suffix = FilenameUtils.getExtension(excel.getOriginalFilename());
        if (FileSuffixConstant.XLS.equalsIgnoreCase(suffix)) {
            workbook = new HSSFWorkbook(excel.getInputStream());
        } else {
            workbook = new XSSFWorkbook(excel.getInputStream());
        }

        Iterator<Sheet> sheetIterator = workbook.sheetIterator();
        boolean result = true;
        while (sheetIterator.hasNext()) {
            Sheet curSheet = sheetIterator.next();
            // 上传题库
            long bankId = uploadQuestionBankByExcel(userId, curSheet);
            // 上传该题库下的题目
            result = result && uploadQuestionByExcel(bankId, curSheet);
        }

        return result;
    }

    /**
     * 读取excel文件上传题库
     *
     * @param userId   用户Id
     * @param curSheet 当前Sheet
     * @return 题库id
     */
    private long uploadQuestionBankByExcel(Long userId, Sheet curSheet) {
        String bankName = curSheet.getSheetName();
        QuestionBank questionBank = new QuestionBank();
        questionBank.setUserId(userId);
        questionBank.setBankName(bankName);
        questionBank.setIsCommon(0);
        questionBankMapper.insert(questionBank);
        return questionBank.getId();
    }

    /**
     * 读取excel文件上传题目
     *
     * @param bankId   题库Id
     * @param curSheet 当前Sheet
     * @return 插入结果
     * @throws Exception 返回自定义异常信息
     */
    private boolean uploadQuestionByExcel(Long bankId, Sheet curSheet) throws Exception {
        List<Question> questionList = new ArrayList<>();
        for (int i = 1; i <= curSheet.getLastRowNum(); i++) {
            Row row = curSheet.getRow(i);
            Question question = new Question();
            question.setBankId(bankId);
            question.setProblem(row.getCell(0).getStringCellValue());
            question.setSolution(row.getCell(1).getStringCellValue());
            question.setTags(row.getCell(2).getStringCellValue());
            String difficult = row.getCell(3).getStringCellValue();
            try {
                question.setDifficulty(QuestionConverter.convertDiffStringToInt(difficult));
            } catch (Exception e) {
                throw new Exception("题目难度存在错误输入，当前第" + (i + 1) + "行:");
            }
            Cell remark = row.getCell(4);
            if (remark != null) {
                question.setRemark(row.getCell(4).getStringCellValue());
            }

            questionList.add(question);
        }
        return questionService.saveBatch(questionList);
    }

    /**
     * 设置行内单元格信息
     *
     * @param row     行实体
     * @param column  开始列
     * @param content 单元格内容
     */
    private void setRow(Row row, int column, String... content) {
        if (content == null || content.length == 0) {
            return;
        }
        for (int i = column; i < column + content.length; i++) {
            row.createCell(i).setCellValue(content[i - column]);
        }
    }
}

